﻿using System;
using System.Collections.Generic;
using ParserGenerator.Collections;
using ParserGenerator.GrammarConstruction;

namespace ParserGenerator.ParserConstruction
{
    [Serializable]
    public sealed class ParserAutomatonItemLookaheadSet : ReadOnlySet<GrammarTerminalSymbol>
    {
        public ParserAutomatonState State { get; internal set; }
        public ParserAutomatonItem Item { get; }
        internal ISet<GrammarTerminalSymbol> UnderlyingSet => Set;

        internal ParserAutomatonItemLookaheadSet(ParserAutomatonState state, ParserAutomatonItem item)
            : this(item)
        {
            if (state == null)
                throw new ArgumentNullException(nameof(state));
            State = state;
        }

        internal ParserAutomatonItemLookaheadSet(ParserAutomatonItem item)
            : this()
        {
            if (item == null)
                throw new ArgumentNullException(nameof(item));
            Item = item;
        }

        internal ParserAutomatonItemLookaheadSet()
            : base(new HashSet<GrammarTerminalSymbol>())
        {
        }

        internal bool Add(GrammarTerminalSymbol token)
        {
            if (token == null)
                throw new ArgumentNullException(nameof(token));
            return Set.Add(token);
        }

        internal bool MergeWith(ParserAutomatonItemLookaheadSet other)
        {
            if (other == null)
                throw new ArgumentNullException(nameof(other));
            if (Set.IsSupersetOf(other.Set))
                return false;
            Set.UnionWith(other.Set);
            return true;
        }

        internal void UnionWith(IEnumerable<GrammarTerminalSymbol> collection)
        {
            if (collection == null)
                throw new ArgumentNullException(nameof(collection));
            Set.UnionWith(collection);
        }

        internal void FilterWith(ParserAutomatonItemLookaheadSet filter)
        {
            if (filter == null)
                throw new ArgumentNullException(nameof(filter));
            Set.IntersectWith(filter.Set);
        }
    }
}
